import TreeNode, { Indexer } from './TreeNode';
import IAdapter from '../interfaces/IAdapter';
import IEnumerator from '../interfaces/IEnumerator';
export default class NodeT2BEnumerator<T, IdxFunc extends Indexer, Adapter extends IAdapter<TreeNode<T>>> implements IEnumerator<TreeNode<T>>{
    //头节点，指向输入的根节点
    private _node: TreeNode<T> | undefined;
    // 枚举器内部持有一个队列或堆栈的适配器，用于存储遍历的元素，指向泛型参数
    private _adapter !: IAdapter<TreeNode<T>>;
    //当前正在操作的节点类型
    private _currNode !: TreeNode<T> | undefined;
    // 当前的Indexer，用于选择从左到右还是从右到左遍历，指向泛型参数
    private _indexer !: IdxFunc;

    // 实现接口放current，用于返回当前正在枚举的节点TreeNode < T > | undefined
    public get current(): TreeNode<T> | undefined {
        return this._currNode;
    }

    /**
     * 
     * @param node { TreeNode < T > | undefined } 要遍历的树结构的根节点
     * @param func { IdxFunc }  IdxFunc extends Indexer 必须是Indexer类型的回调函数
     * @param adapter { Adapter } 必须是实现IAdapter < TreeNode < T > > >接口的类，该类必须要实现无参数的构造函数(new ( ) => Adapter )
     */
    public constructor(node: TreeNode<T> | undefined, func: IdxFunc, adapter: new () => Adapter) {
        // 必须要有根节点，否则无法遍历
        if (node === undefined) {
            return;
        }
        //头节点，指向输入的根节点
        this._node = node;
        //设置回调函数
        this._indexer = func;
        //调用new回调函数
        this._adapter = new adapter();
        //初始化时将根节点放入堆栈或队列中去
        this._adapter.add(this._node);
        //设定当前node为undefined
        this._currNode = undefined;
    }

    /**
     * *实现接口方法，将枚举器设置为初始化状态，调用reset函数后，可以重用枚举器
     */
    public reset(): void {
        if (this._node === undefined) {
            return;
        }
        this._currNode = undefined;
        this._adapter.clear();
        this._adapter.add(this._node);
    }

    /**
     * *实现接口函数moveNext , 返回false表示枚举结束，否则返回true
     */
    public moveNext(): boolean {
        //当队列或者栈中没有任何元素，说明遍历已经全部完成了，返回false
        if (this._adapter.isEmpty) {
            return false;
        }
        //弹出头或尾部元素，依赖于adapter是stack还是queue
        this._currNode = this._adapter.remove();
        // 如果当前的节点不为undefined
        if (this._currNode != undefined) {
            // 获取当前的节点的儿子节点个数
            let len: number = this._currNode.childCount;
            // 遍历所有的儿子节点
            for (let i = 0; i < len; i++) {
                // 儿子节点是从左到右，还是从右到左进入队列或堆栈
                // 注意，_indexer是在这里调用的
                let childIdx: number = this._indexer(len, i);
                let child: TreeNode<T> | undefined = this._currNode.getChildAt(childIdx);
                if (child !== undefined) {
                    this._adapter.add(child);
                }
            }
        }
        return true;
    }
}